#include "StdAfx.h"
#include "Shader.h"

#include "DynamicRHI.h"

#include "logmanager.h"

using namespace RenderSystem;
using namespace Common;

extern void BeginCompileShader( VertexFactoryType* pVFType, ShaderType* pType, 
	const TCHAR* pszSourceFilename,
	const TCHAR* pszEntryFunctionName,
	const ShaderProfile& rShaderProfile,
	const ShaderCompilerEnvironment& rShaderCompilerEnvironment
	);


//////////////////////shader Parameters//////////////////////////////////////////
void ShaderParameter::Bind(const ShaderParameterMap& rParameterMap,const TCHAR* pszParameterName, bool bOptional)
{
	WORD UnusedSamplerIndex = 0;
	if( !rParameterMap.FindParameterAllocation( pszParameterName, m_BufferIndex, m_BaseIndex, m_NumBytes, UnusedSamplerIndex ) && !bOptional )
	{
		LogManager::getSingleton() << TEXT("Failure to bind non-optional shader parameter:")
			<< pszParameterName
			<< TEXT(".The parameter is either not present in the shader, or the shader compiler optimized it out.");

		LogManager::getSingleton().outputMsg();
	}
}

void ShaderTextureParameter::Bind(const ShaderParameterMap& rParameterMap,const TCHAR* pszParameterName, bool bOptional )
{
	WORD UnusedBufferIndex = 0;
	if(!rParameterMap.FindParameterAllocation( pszParameterName, UnusedBufferIndex, m_BaseIndex, m_NumTextures, m_SamplerIndex ) && !bOptional )
	{
		LogManager::getSingleton() << TEXT("Failure to bind non-optional shader texture parameter:")
			<< pszParameterName
			<< TEXT(".The parameter is either not present in the shader, or the shader compiler optimized it out.");

		LogManager::getSingleton().outputMsg();
	}
}

//////////////////////shader////////////////////////////////////////////
Shader::Shader( const CompiledShaderInitializerType& rInitializer )
	:m_pShaderType(rInitializer.Type),m_pVertexShader(NULL),m_pPixelShader(NULL),
	m_ShaderKey(rInitializer.strCodes, rInitializer.ParameterMap), m_uNumInstructions(rInitializer.NumInstructions)
{
}

Shader::Shader( void )
		:m_pShaderType(NULL),m_pVertexShader(NULL),m_pPixelShader(NULL),m_uNumInstructions(0)
{
}

Shader::~Shader(void)
{
}

//////////////////////shader type/////////////////////////////////////////
ShaderType::ShaderTypes& ShaderType::GetTypeSets()
{
	static ShaderTypes shaderTypes;
	return shaderTypes;
}

void ShaderType::BeginCompileShader(VertexFactoryType* pVFType, const ShaderProfile& rShaderProfile, const ShaderCompilerEnvironment& rEnvironment)
{
	// Allow the shader type to modify its compile environment.
	ShaderCompilerEnvironment rModifiedEnvironment = rEnvironment;
	(*ModifyCompilationEnvironmentRef)(rModifiedEnvironment);

	// Compile the shader environment passed in with the shader type's source code.
	::BeginCompileShader(
		pVFType,
		this,
		m_szSourceFilename,
		m_szEntryFunctionName,
		rShaderProfile,
		rModifiedEnvironment
		);
}

Shader* ShaderType::_FindShaderByOutput( const ShaderCompilerOutput& rOutput )
{
	struct FindShaderFunc
	{
		FindShaderFunc( const ShaderKey& rShaderKey )
			:m_rShaderKey(rShaderKey)
		{
		}

		bool operator() ( const Shader* pShader ) const
		{
			if( pShader->GetShaderKey().m_dwParameterMapCRC == m_rShaderKey.m_dwParameterMapCRC )
				return true;

			return false;
		}

	private:

		const ShaderKey& m_rShaderKey;
	};

	ShaderKey shaderKey(rOutput.m_strCodes, rOutput.m_ParameterMap);
	ShaderCodeMapsConstIterator itrResult = std::find_if( m_ShaderCodeMap.begin(), m_ShaderCodeMap.end(), FindShaderFunc(shaderKey) );
	if( itrResult == m_ShaderCodeMap.end() )
		return NULL;

	return *itrResult;
}
